package cn.lg.soar.cms.biz.modules.other.service.impl;

import cn.lg.soar.cms.api.model.RegionDTO;
import cn.lg.soar.cms.biz.modules.other.entity.Region;
import cn.lg.soar.cms.biz.modules.other.mapper.RegionMapper;
import cn.lg.soar.cms.biz.modules.other.model.RegionTreeCache;
import cn.lg.soar.cms.biz.modules.other.service.IRegionService;
import cn.lg.soar.common.data.tree.ITreeResult;
import cn.lg.soar.common.util.current.CurrentProxy;
import cn.lg.soar.core.config.cache.template.ICacheTemplate;
import cn.lg.soar.database.base.service.impl.BaseServiceImpl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Region服务层实现
 * 区域
 * @author luguoxiang
 * @since 2022-08-04
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class RegionServiceImpl extends BaseServiceImpl<RegionMapper, Region> implements IRegionService, CurrentProxy<IRegionService> {

    private static final com.github.benmanes.caffeine.cache.Cache<String, List<RegionTreeCache>> CACHE = Caffeine.newBuilder()
            .initialCapacity(4)
            .maximumSize(4)
            .expireAfterWrite(Duration.ofSeconds(120))
            .build();

    @Autowired
    private ICacheTemplate<String, Object> cacheTemplate;

    @Override
    public boolean save(Region entity) {
        CACHE.invalidateAll();
        cacheTemplate.delete("tree:region");
        return super.save(entity);
    }

    @Override
    public boolean updateById(Region entity) {
        CACHE.invalidateAll();
        cacheTemplate.delete("tree:region");
        return super.updateById(entity);
    }

    @Override
    public List<RegionTreeCache> tree() {
        return CACHE.get("tree:region", k -> {
            Object o = cacheTemplate.get(k);
            if (o != null) {
                return JSON.parseArray((String) o, RegionTreeCache.class);
            }
            return doRefreshCache();
        });
    }

    @Override
    public List<RegionTreeCache> tree(Integer parentId) {
        List<RegionTreeCache> tree = proxy().tree();
        if (parentId == null) {
            return tree;
        }
        if (!Objects.equals(0, parentId)) {
            tree = RegionTreeCache.findChildren(tree, parentId);
        }
        if (tree == null) {
            return Collections.emptyList();
        }
        return tree.stream()
                .map(x -> new RegionTreeCache(x.getValue(), x.getLabel(), x.getDisabled(), null))
                .collect(Collectors.toList());
    }


    @Override
    public List<RegionDTO> getRegionPath(int id) {
        // 获取省
        List<RegionTreeCache> tree = proxy().tree();
        List<RegionTreeCache> link = RegionTreeCache.findLink(tree, x -> Objects.equals(x.getValue(), id));
        Collections.reverse(link);
        return link.stream()
                .map(x -> {
                    RegionDTO dto = new RegionDTO();
                    dto.setId(x.getValue());
                    dto.setName(x.getLabel());
                    return dto;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getNameList(int id) {
        List<RegionTreeCache> tree = proxy().tree();
        List<RegionTreeCache> link = RegionTreeCache.findLink(tree, x -> Objects.equals(x.getValue(), id));
        Collections.reverse(link);
        return link.stream()
                .map(RegionTreeCache::getLabel)
                .collect(Collectors.toList());
    }

    @Override
    public Map<Integer, List<String>> getNameListMap(Collection<Integer> ids) {
        Map<Integer, List<String>> map = new HashMap<>(ids.size());
        for (Integer id : ids) {
            map.put(id, getNameList(id));
        }
        return map;
    }

    @Scheduled(cron = "0 10 3 * * ? ")
    public void refreshCache() {
        // 利用缓存（当使用redis时）实现部署多个微服务实例时，没十分钟只会执行一次
        String key = "lock-refresh-region";
        boolean b = cacheTemplate.putIfAbsent(key, 1, Duration.ofHours(23));
        if (b) {
            try {
                doRefreshCache();
            } catch (RuntimeException e) {
                cacheTemplate.delete(key);
            }
        }
    }

    private List<RegionTreeCache> doRefreshCache() {
        List<Region> list = list(
                Wrappers.<Region>lambdaQuery()
                        .select(Region::getId, Region::getName, Region::getStatus)
                        .orderByAsc(Region::getSort)
        );

        List<RegionTreeCache> tree = ITreeResult.valueOf(
                list,
                0,
                (x, cs) -> new RegionTreeCache(x.getId(), x.getName(), x.getStatus() == 1, cs)
        );

        String jsonString = JSON.toJSONString(tree);

        cacheTemplate.put("tree:region", jsonString, Duration.ofHours(25));
        return tree;
    }

}
